package com.bakend.common.utils;

import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClaims;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: dengfan
 */
@Slf4j
public class JwtUtils {

    //    private static final long EXPIRE = 1 * 60 * 60 * 1000; //过期时间
    private static final long EXPIRE = 10 * 1000; //过期时间
    private static final long REFRESHTIME = 1 * 60 * 60 * 1000; //过期时间
    public   static final String UserIdKey = "userCode";
    public   static final String RefeshKey = "refreshTime";


    public static final String key = "NiuLeiNiubeee";//密钥

    /**
     * 生成token
     *
     * @param claims 要传送消息map
     * @return
     */
    public static String generateToken(Map<String, Object> claims) {

        Date nowDate = new Date();
        claims.put(RefeshKey, nowDate.getTime());
        //过期时间,设定为一分钟
        Date expireDate = new Date(System.currentTimeMillis() + EXPIRE);
        //头部信息,可有可无
        Map<String, Object> header = new HashMap<>(2);
        header.put("type", "jwt");

        //更强的密钥,JDK11起才能用
        //  KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
        //  PrivateKey key1 =  keyPair.getPrivate();  // 私钥
        //PublicKey key2 =  keyPair.getPublic();  //公钥

        return Jwts.builder().setHeader(header)
                // .setSubject("token")//主题
                // .setIssuer("bakend") //发送方
                .setClaims(claims)  //自定义claims
                .setIssuedAt(nowDate)//当前时间
                .setExpiration(expireDate) //过期时间
                .signWith(SignatureAlgorithm.HS256, key)//签名算法和key
                .compact();
    }


    /**
     * 校验是不是jwt签名
     *
     * @param token
     * @return
     */
    public static boolean isSigned(String token) {
        return Jwts.parser()
                .setSigningKey(key)
                .isSigned(token);
    }

    /**
     * 校验签名是否正确
     *
     * @param token
     * @return
     */
    public static boolean verify(String token) {
        try {
            Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token);
            return true;
        } catch (JwtException e) {
            System.out.println(e.getMessage());
            return false;
        }
    }

    /**
     * 获取payload 部分内容（即要传的信息）
     * 使用方法：如获取userId：getClaim(token).get("userId");
     *
     * @param token
     * @return
     */
    public static Claims getClaim(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return claims;
    }

    /**
     * 获取头部信息map
     * 使用方法 : getHeader(token).get("alg");
     *
     * @param token
     * @return
     */
    public static JwsHeader getHeader(String token) {
        JwsHeader header = null;
        try {
            header = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token)
                    .getHeader();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return header;
    }

    /**
     * 获取jwt发布时间
     */
    public static Date getIssuedAt(String token) {
        Claims claim = getClaim(token);
        return claim == null ? null : claim.getIssuedAt();
    }

    /**
     * 获取jwt失效时间
     */
    public static Date getExpiration(String token) {
        Claims claim = getClaim(token);
        return claim == null ? null : claim.getExpiration();
    }

    /**
     * 验证token是否需要刷新
     *
     * @param token
     * @return true:需要刷新   false:不需要刷新
     */
    public static boolean needRefresh(String token) {
        try {
            Claims claims = getClaim(token);
            final Date expiration = new Date(Long.parseLong((String) claims.get(RefeshKey)));
            return expiration.before(new Date());
        } catch (ExpiredJwtException expiredJwtException) {
            return true;
        }
    }
    /**
     * 刷新token
     *
     * @param oldToken   旧token
     * @return 刷新后的token
     */
    public static String refreshToken(String oldToken) {
        Claims claims = null;
        Object userId  = null;
        try {
            claims = getClaim(oldToken);
            userId = claims.get(UserIdKey);
        } catch (Exception exception) {
        }
        if(claims ==null){
            try {
                Map<String,Object> parse = (Map<String, Object>) JSON.parse(getPayloadByBase64(oldToken));
                userId = parse.get(UserIdKey);
            }catch (Exception e){
                log.error("解析token失败。token="+oldToken);
            }
        }
        if(userId==null){
            return null;
        }
        Map<String,Object> map = new HashMap<>();
        map.put(UserIdKey,userId);
        return generateToken(map);
    }

    /**
     * 直接Base64解密获取header内容
     *
     * @param token
     * @return
     */
    public static String getHeaderByBase64(String token) {
        String header = null;
        if (isSigned(token)) {
            try {
                byte[] header_byte = Base64.getDecoder().decode(token.split("\\.")[0]);
                header = new String(header_byte);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        return header;
    }

    /**
     * 直接Base64解密获取payload内容
     *
     * @param token
     * @return
     */
    public static String getPayloadByBase64(String token) {
        String payload = null;
        if (isSigned(token)) {
            try {
                byte[] payload_byte = Base64.getDecoder().decode(token.split("\\.")[1]);
                payload = new String(payload_byte);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        return payload;
    }

    public static void main(String[] args) {
        //用户自定义信息claims
        Map<String, Object> map = new HashMap<>();
        map.put("userId", "test122");
        String token = generateToken(map);
        System.out.println(token);

        token = "eyJ0eXBlIjoiand0IiwiYWxnIjoiSFMyNTYifQ.eyJyZWZyZXNodGltZSI6MTYxOTY5MzE0NTgwOSwiZXhwIjoxNjE5NjkzMTU1LCJ1c2VySWQiOiJ0ZXN0MTIyIiwiaWF0IjoxNjE5NjkzMTQ1fQ.AgqBlYm5_hFN7yUUBaUVC6wvCCKJOZTCtTkBREZsxFQ";
        System.out.println(getPayloadByBase64(token));
        System.out.println("claim:" + getClaim(token).get("userId"));
//        System.out.println("header:" + getHeader(token));
        //    System.out.println(getIssuedAt(token));
        Claims claims = getClaim(token);

        //  System.out.println(getHeaderByBase64(token));
        System.out.println(getPayloadByBase64(token));

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy‐MM‐dd hh:mm:ss");
        System.out.println("签发时间:" + sdf.format(claims.getIssuedAt()));
        System.out.println("过期时间:" + sdf.format(claims.getExpiration()));
        System.out.println("当前时间:" + sdf.format(new Date()));

    }

    public static Object parseTokenGetUserId(String token) {
        Claims claim = getClaim(token);
        if(claim!=null) return claim.get(UserIdKey);
        return null;
    }
}


